package com.example.big_event.controller;


import com.example.big_event.pojo.Result;
import com.example.big_event.pojo.User;
import com.example.big_event.service.UserService;
import com.example.big_event.utils.Md5Util;
import com.example.big_event.utils.ThreadLocalUtil;
import com.example.big_event.utils.jwtUtil;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Validated//限定实体类中的属性
@RestController//声明这个一个控制类
@RequestMapping("/user")//统一路径管理
public class UserController {

    @Autowired//注解注入service的实现类对象
    private UserService service;

    @Autowired//注解注入redis的实现类对象 StringRedisTemplate
    private StringRedisTemplate stringRedisTemplate;

    //注册方法
    @PostMapping("/register")//注册功能  请求携带用户名和密码
    public Result register(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$") String password){

        //查询用户
        User user = service.findByuserUserName(username);

        //判断用户名
        if(user==null){
            //查询为空
            //注册

            //调用注册方法
            service.register( username, password);

            //返回成功信息
            return Result.success();
        }
        //返回错误信息,已被占用
        else {
            return Result.erro("用户名已存在");
        }

    }

    @PostMapping("/login")//登录功能  请求携带用户名和密码
    //方法中对于传入的参数需要进行@Pattern（regexp的校验）
    public Result login(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$") String password){

        //调用service对象中的方法去数据库中查找是否有这个传入参数相关的对象 并且获取到这个对象
        User user = service.findByuserUserName(username);

        //判断获取到的对象是否为空或者是否存在
        if (user==null){
            return Result.erro("用户不存在");
        }

        //判断从参数中获取到的密码加密过后的密码和数据库中的密码进行对比看是否一致
        if (Md5Util.getMD5String(password).equals(user.getPassword())){
            //密码一致 通过

            //创建一个map集合储存这个用户的用户名和id
            Map<String,Object> claims = new HashMap<>();
            claims.put("id",user.getId());
            claims.put("username",user.getUsername());

            //调用生成令牌的工具类根据map集合生成令牌
            String token = jwtUtil.gereratetoken(claims);

            //将token存入到Redis中
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            operations.set(token,token,30, TimeUnit.MINUTES);

            //返回成功信息
            return Result.success(token);
        }

        //返回失败信息
        return Result.erro("密码错误");

    }



    @GetMapping("/userinfo")//获取用户详细信息功能   请求携带token令牌
    public Result<User> userinfo(@RequestHeader(name = "Authorization") String token){


        /*Map<String, Object> map = jwtUtil.parse(token);
        String username =(String) map.get("username");*/

        //通过ThreadclocalUtil获取到map集合
       Map<String,Object> map = ThreadLocalUtil.get();

       //根据username键获取到map集合中的username信息
        String username = (String) map.get("username");

        //根据service对象中的Byusername方法查找到用户对象
        User user = service.findByuserUserName(username);

        //返回用户对象的信息
        return Result.success(user);
    }


    @PutMapping("/update")//更新用户 （修改用户的昵称和照片）
    public Result update(@RequestBody @Validated User user){//@Validated用于限定user实体类中的一些属性，比如@URL，@JSONIgnore

        //service对象调用update方法，需要传入user对象
        service.update(user);

        //返回成功信息
        return  Result.success();

    }

    @PutMapping("/avartar")//更换头像  虽然我也不知道为什么又要单独写一份这个功能

    //传入图片地址 请求方法中对图片的信息进行校验 检查其是否是url格式
    public Result updateavatar(@RequestParam @URL String avartarurl){//@RequestParam标明需要从这个参数获取信息 @URL限制avartarurl需要是一个url

        //service调用更新头象方法
        service.updateavartar(avartarurl);

        //返回成功信息
        return Result.success();

    }



    @PutMapping("/updatepassword")//更新密码方法
    //略微复杂.......
    //前端发送一个令牌和一个json格式的带有新旧密码和确认密码的Put请求 后端需要在参数校验中将这个json字符串解析为一个map集合，键是字符串
    //值是对应json中的属性

    //获取map集合 携带token令牌
    public Result updatepassword(@RequestBody Map<String,String> map, @RequestHeader(name = "Authorization") String token){
        //从map集合中通过get方法获取到键对应的值
        String oldPassword = map.get("OldPassword");
        String newPassword = map.get("NewPassword");
        String rePassword = map.get("RePassword");

        /*
        * 获取到密码以后判断三个密码
        * 1 --  判断三个密码是否为空 返回失败信息
        * 2 -- 判断旧密码是否正确
        * 3 -- 对比新密码和确认密码是否一致
        * 4 -- 校验全部通过 删除旧密码 调用service方法设置新密码*/

        //检查三个密码是否是空值
        if(!StringUtils.hasLength(oldPassword) || !StringUtils.hasLength(newPassword) ||
                !StringUtils.hasLength(rePassword)){
            //返回失败信息
           return Result.erro("缺少必要的参数");
        }


        Map<String,String> map1 = ThreadLocalUtil.get();

        String username =(String)map1.get("username");

        User user = service.findByuserUserName(username);

        //检查旧密码是否正确
        if (!user.getPassword().equals(Md5Util.getMD5String(oldPassword))){
           return Result.erro("原密码不正确");
        }

        //对比新密码和确定密码是否一致
        if (!newPassword.equals(rePassword)){
           return Result.erro("新密码跟确定密码不一致");
        }

        //调用service更新密码
        service.updatepassword(newPassword);

        //删除原来的token（令牌）
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        operations.getOperations().delete(token);//删除redis中的旧令牌


        //返回成功信息
        return Result.success();

    }




}